13

本文翻译自https://www.sitepoint.com/how...

在本文中,我将介绍Velocity.js,这是一个快速,高性能的JavaScript动画引擎。当您浏览完所有的demo时,您可以使用Velocity.js创建自己的动画,并使您的网站更具互动性和用户友好性。本文所讲内容不使用jQuery。

Velocity.js功能概览

Velocity.js是一个功能强大的库,它将DOM置于你的指尖!它的动画涵盖:

  • CSS动画属性的数值,包括颜色

  • Transform(变换)

  • SVG属性

  • 滚动事件,相对于页面或页面中的容器元素

  • 淡入淡出动画

一般来说,Velocity一次可以操控一个数值属性值的动画。
例如,如果要沿X和Y坐标移动元素,则不能使用translate['10px', '15px']。 相反,应该将translate属性与其相应的轴结合在一起,如:translateX:'10px',translateY:'15px'
Velocity有一个功能称为forcefeeding,它可以让你同时指定两个值。 将在本文后面介绍这个功能。


配置项

Velocity的配置项在制作动画时给予了相当的灵活性。

以下是本文的demo中将会看到的配置项:

  • Durantion:每个动画持续的时间,测量单位为毫秒。

  • Easing:Velocity支持大多数的easing类型。easeease-inease-out, ease-in-out,贝塞尔曲线,甚至是很酷的物理弹簧效果。 可以在这个demo中查看弹簧效果:https://codepen.io/mengmengpr...

  • Loop:动画应该重复的次数。如果将此选项设置为true,它将无限期运行。

  • Delay:动画开始之前的延迟时长。

全部的配置项可以在Velocity的官网查看,此处也附上Velocity中文网站


语法

如果你使用jQuery,Velocity.js可以轻松上手。 事实上,Velocity与jQuery具有相同的API:
下载Velocity,引入你的项目,然后将$.animate()替换成$.velocity()

但是,你也可以不用jQuery来使用Velocity,并且本文中的demo也将不使用jQuery。语法与使用jQuery的方式有所不同:

Velocity(element, {property: value}, {option: optionValue});

要在同一个元素上链接另一个动画,只需在之前的velocity后再添加一个:

Velocity(element1, {property: value}, {option: optionValue});
Velocity(element1, {property: value}, {option: optionValue});

要将动画同时应用于多个元素,只需将所有元素存储到变量中,并将Velocity应用于该变量,无需通过循环实现:

const elements = document.querySelectorAll('<div>');
Velocity(elements, {property: value}, {option: optionValue});

对于选项值单位,你可以使用px,%,rem,em,vw/vh和deg。如果不添加单位,Velocity将提供适当的单位,通常为px。

forcefeeding功能:传递初始值

这个功能可以让你不用Velocity.js查询DOM以获取元素的初始值,而使用以下语法自行设置:

Velocity(element, {
  translateX: [endValue, startValue],
  backgroundColor: [endValue, easing, startValue]
}, {
  //options here
});

在上面的代码中,translateXbackgroundColor分别设置了一个数组:

  • 第一个值代表动画的结束状态。

  • 第二个值(可选)是特定属性的easing选项。

  • 第三个值即是指定动画的起始状态。

你可以去这里阅读更详细的forcefeeding

控制Velocity.js动画

您可以使用以下语法停止,暂停,反向以及恢复元素上的所有Velocity调用:

  • 停止:Velocity(elem, 'stop')

  • 暂停:Velocity(elem, 'pause')

  • 反向:Velocity(elem, 'reverse')

  • 恢复:Velocity(elem, 'resume')

根据这些基本指导,你可以开始进入一些实际的例子。


Demo: 掉落的小球

我们从一个由顶部落下的球开始。

const ball = document.querySelector('.ball');

Velocity(ball, {
    translateY: '200px'
}, {
    easing: [2000, 15],
    durantion: 3000
});

上面的代码选择了一个class为ball的HTML元素,它在Y轴上移动200px,持续3秒。随着小球的下落不断加速,并在最后得到弹性。

你可以使用Velocity的弹簧效果快速实现此功能,通过向velocity的easing选项传递一个数组:第一个数组项表示张力,第二个表示摩擦。
高张力值会增加总速度和波峰(默认值为500),较低的摩擦值会增加振动速度(默认值为20)。

为了好玩,我们让球的背景颜色从蓝色的初始值变成深色。 要设置背景颜色的初始值,您需要使用Velocity.js的forcefeeding

Velocity(ball, {
    translateY: '130px',
    backgroundColor: ['#222', '#043d99']
}, {
    easing: [2000, 15],
    duration: '3000'
});

具体实现效果点此看看:
https://codepen.io/mengmengpr...


Demo:按钮控制的弹簧小球

接下来的这个demo,目标是创建一个动画序列:

  • 小球从顶端落下

  • 当小球撞击地面的时候样式有所挤压

  • 当小球反弹回来的时候样式恢复正常

  • 这个动画会一直循环

  • 你可以通过一个按钮控制动画的循环和停止

实现这种动画需要将各种各样的片断连在一起,并使用按钮来整体控制它们的动画。

理想的工具将是一个时间表,它将涵盖所有的片断,并可以控制所有片断的开始和结束。Velocity.js没有原生的时间轴,但有几个解决方案:

  • 使用Tweene - 这是一个动画代理,是一个可以使用很多Javascript动画库的包装器,包括Velocity.js。Tweene需要Velocity使用jQuery,本文未使用jQuery,所以暂不考虑。

  • JavaScript的requestAnimationFrame()。这是一个原生API,用于在浏览器环境中运行任何平滑,高效的动画,例如CSS,画布等。目前除了Opera Mini外,所有主流浏览器都支持。

将片断分割成函数

为了保持代码整洁,可以根据你需要的动画场景构建一个函数。 然后,只需要在主函数中调用这些函数,主函数包含requestAnimationFrame()方法。

const changeBallPosition = (elem, propVal, easingVal, durationVal) => {
    Velocity(elem, {
        translateY: propVal
    }, {
        easing: easingVal, 
        duration: durationVal
    });
};

const changeBallWidth = (elem, propVal, easingVal, durationVal) => {
    Velocity(elem, {
        scaleX: propVal
    }, {
        easing: easingVal,
        duration: durationVal
    });
};

上面的代码片段包含了如何编写ES6箭头函数的示例。
每个函数使用const关键字存储在常量中。如果需要在整个程序中存储需要更新的值,请改用let

可以看到,每个功能都调用了Velocity来让小球进行特定的移动。注意,要移动球并更改其宽度,代码没有分别更改CSS的topwidth。相反,它改变了translatescale的值,从而带来更好效的动画效果。

下面是有计时器的主函数。在主函数里调用以上函数:

let animationFrameId;
const launchBall = (elem) => {
    changeBallPosition(elem, '130px', 'easeInQuart', 300);
    changeBallWidth(elem, 1.2, 'linear', 50);
    changeBallWidth(elem, 1, 'linear', 50);
    changeBallPosition(elem, '-10px', 'easeOutQuart', 300);
    changeBallWidth(elem, 1, 'linear', 50);
    animationFrameId = requestAnimationFrame(() => {
        launchBall(elem);
    });
};

注意全局变量animationFrameId。后面将需要在cancelAnimationFrame()中用这个变量停止动画。

要使球运动,需要在按钮的点击事件中调用launchBall()函数,我们需要把小球这个变量传递给函数:

btnPlay.addEventListener('click', function () {
    launchBall(ball);
    this.enabled = true;
    btnStop.disabled = false;
});

注意,在这个点击函数的回调中用了this关键字,这里的this指向被点击的按钮。如果使用箭头函数,this关键字将引用全局的window对象。简而言之,不要在动态上下文的回调函数中使用箭头函数。

为了让小球停止,需要一个新的函数:

const removeAnimFrame = () => {
    if (animationFrameId) {
        cancelAnimationFrame(animationFrameID);
    }
}

在这里,你通过传递animationFrameId来调用cancelAnimationFrame()animationFrameId包含一个对小球循环动画的引用。

停止动画的点击事件:

btnStop.addEventListener('click', function () {
    removeAnimFrame();
    Velocity(ball, 'stop', true);
    this.disabled = true;
    btnPlay.disabled = false;
});

有趣的是,调用Velocity的stop()方法时用了一个额外的布尔值。这是清除动画队列所必需的。如果你不用这个参数,点击停止按钮,球不会立即停止动画。等所有排队的Velocity调用完成执行,它才会停止动画。

具体实现效果请看如下demo:
https://codepen.io/mengmengpr...

中文版下已经出炉,点击这里直达。


Mengpro
1.6k 声望123 粉丝

I love my job, job makes me happy!?